#include "StatusServiceImpl.h"
#include "configMgr.h"
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#include "RedisMgr.h"

static std::string generate_unique_string()
{
	boost::uuids::uuid uuid = boost::uuids::random_generator()();

	std::string unique_string = boost::uuids::to_string(uuid);
	return unique_string;
}
StatusServiceImpl::StatusServiceImpl():_server_index(0)
{
	auto& config = configMgr::GetInst();
	auto server_list = config["ChatServers"]["name"];
	std::vector<std::string> words;
	std::stringstream ss(server_list);
	std::string word;
	while (std::getline(ss, word, ','))
	{
		words.push_back(word);
	}
	for (auto& word : words)
	{
		ChatServer server;
		server.port = config[word]["port"];
		server.host = config[word]["host"];
		server.name = word;
		_servers[word] = server;
	}
}

grpc::Status StatusServiceImpl::GetChatServer(ServerContext* context, const GetChatServerReq* request, GetChatServerRsp* reply)
{
	std::string prefix("status server receive: ");
	_server_index = (_server_index++) % _servers.size();
	auto server = getChatServer();
	reply->set_host(server.host);
	reply->set_port(server.port);
	reply->set_error(ErrorCodes::Success);
	reply->set_token(generate_unique_string());
	insertToken(request->uid(), reply->token());
	return grpc::Status::OK;


}

grpc::Status StatusServiceImpl::Login(ServerContext* context, const message::LoginReq* request, message::LoginRsp* reply)
{
	auto uid = request->uid();
	auto token = request->token();
	std::string uid_str = std::to_string(uid);
	std::string token_key = USERTOKENPREFIX + uid_str;
	std::string token_val = "";
	bool success = RedisMgr::GetInstance().Get(token_key, token_val);
	if (!success)
	{
		reply->set_error(ErrorCodes::UidInvalid);
		return grpc::Status::OK;
	}
	if (token_val != token)
	{
		reply->set_error(ErrorCodes::TokenInvalid);
		return grpc::Status::OK;
	}
	reply->set_error(ErrorCodes::Success);
	reply->set_uid(uid);
	reply->set_token(token);
	return grpc::Status::OK;
}

ChatServer StatusServiceImpl::getChatServer()
{
	std::lock_guard<std::mutex> lock(_mtx);
	auto minServer = _servers.begin()->second;
	auto count_str = RedisMgr::GetInstance().HGet(LOGIN_COUNT, minServer.name);
	if (count_str.empty())
	{
		minServer.con_count = INT_MAX;
	}
	else {
		minServer.con_count = std::stoi(count_str);
	}

	for (auto& server : _servers) {
		if (server.second.name == minServer.name)
		{
			continue;
		}
		auto count_str = RedisMgr::GetInstance().HGet(LOGIN_COUNT, server.second.name);
		if (count_str.empty()) {
			server.second.con_count = INT_MAX;
		}
		else {
			server.second.con_count = std::stoi(count_str);
		}
		if (server.second.con_count < minServer.con_count) {
			minServer = server.second;
		}
	}
	return minServer;
}

void StatusServiceImpl::insertToken(int uid,std::string token)
{
	std::string uid_str = std::to_string(uid);
	std::string token_key = USERTOKENPREFIX + uid_str;
	RedisMgr::GetInstance().Set(token_key, token);
}
